package cn.demoncat.util.lang;

import cn.demoncat.util.exception.ParamRuntimeException;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;

/**
 * 描述：Double工具
 *
 * @author 延晓磊
 *
 * @since 2017年7月10日
 */
public final class DoubleUtil {

	/**
	 * 判断为null或0
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月16日
	 */
	public static boolean isEmpty(Double o) {
		return o == null || o == 0;
	}

	/**
	 * 判断非空或0
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年1月16日
	 */
	public static boolean isNotEmpty(Double o) {
		return !isEmpty(o);
	}

	/**
	 * 判断为空或0时抛异常
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2022年03月25日
	 */
	public static Double checkEmpty(Double o){
		if (isEmpty(o)) {
			throw ParamRuntimeException.NULL;
		}
		return o;
	}

	/**
	 * null转0
	 * 
	 * @param o
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static Double toEmpty(Double o) {
		return o == null ? 0 : o;
	}
	
	/**
	 * null/0 转默认值
	 * 
	 * @param o		数据
	 * @param def	默认值
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年6月5日
	 */
	public static Double toDefault(Double o, Double def) {
		return isEmpty(o) ? def : o;
	}

	/**
	 * 转换为字符串
	 *
	 * @param o
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年11月23日
	 */
	public static String toString(Double o){
		return o == null ? null : NumberUtil.format(o, "#.#########");
	}

	/**
	 * 转换为字符串
	 *
	 * @param o
	 * @param def
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年11月23日
	 */
	public static String toString(Double o, Double def){
		return o == null ? toString(def) : o.toString();
	}

	/**
	 * 判断是否为整数
	 * 
	 * @param num
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年7月19日
	 */
	public static boolean isInteger(double num) {
		return Math.floor(num) == num;
	}

	/**
	 * 转换字符串为Double
	 *
	 * @param num
	 * @param def	默认值
	 * @return 如果字符串为空则返回def，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Double valueOf(String num, Double def) {
		num = StringUtils.trimToNull(num);
		// 如果为空，返回def
		if (StringUtil.isBlank(num)) {
			return def;
		}
		// 非空转换，格式错误抛异常
		return Double.valueOf(num);
	}

	/**
	 * 转换字符串为Double
	 *
	 * @param num
	 * @return 如果字符串为空则返回null，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Double valueOf(String num) {
		return valueOf(num, null);
	}

	/**
	 * 转换字符串为Double
	 *
	 * @param num
	 * @return 如果字符串为空则返回0，如果字符串非数值则异常
	 *
	 * @author 延晓磊
	 *
	 * @since 2017年1月5日
	 */
	public static Double valueOfZero(String num) {
		return valueOf(num, 0D);
	}

	/**
	 * 转换Object为Double
	 * 
	 * @param num
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020-9-15
	 */
	public static Double cast(Object num) {
		if (num == null) {
			return null;
		}
		if (num instanceof Double) {
			return (Double)num;
		}
		if (num instanceof Number) {
			return ((Number)num).doubleValue();
		}
		String str = num.toString();
		if (str.matches(RegexpUtil.NumberRex.ALL)) {
			return valueOf(num.toString());
		}
		return null;
	}

	/**
	 * 四舍五入
	 *
	 * @param num
	 * @param size	精度
	 * @param mode	进位模式
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static double toFixed(double num, int size, RoundingMode mode) {
		return BigDecimal.valueOf(num).setScale(size, mode).doubleValue();
	}

	/**
	 * 四舍五入
	 * 
	 * @param num
	 * @param size	精度（四舍五入）
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static double toFixed(double num, int size) {
		return toFixed(num, size, RoundingMode.HALF_UP);
	}

	/**
	 * 四舍五入
	 * 
	 * @param num
	 * @param size	精度（四舍五入）
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static double toFixed(String num, int size) {
		return toFixed(valueOfZero(num), size);
	}

	/**
	 * 比例计算（向下进位）
	 * 
	 * @param n1
	 * @param n2
	 * @return 99.99 - 0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static double toRatio(long n1, long n2) {
		return BigDecimal.valueOf(100).multiply(BigDecimal.valueOf(n1)).divide(BigDecimal.valueOf(n2),2, RoundingMode.FLOOR).doubleValue();
	}

	/**
	 * 比例计算（向下进位）
	 * 
	 * @param n1
	 * @param n2
	 * @return 99.99 - 0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static double toRatio(double n1, double n2) {
		if (n1 == 0 || n2 == 0) {
			return 0;
		}
		return BigDecimal.valueOf(100).multiply(BigDecimal.valueOf(n1)).divide(BigDecimal.valueOf(n2),2, RoundingMode.FLOOR).doubleValue();
	}

	/**
	 * 将Double转换为Integer
	 * 
	 * @param 	d
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static int toInt(double d) {
		return (int) d;
	}

	/**
	 * 将Double转换为Long
	 * 
	 * @param 	d
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年5月31日
	 */
	public static long toLong(double d) {
		return (long) d;
	}

	/**
	 * 运算：加 +
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static double add(double ...vs) {
		if (vs == null) {
			return 0D;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return BigDecimal.valueOf(vs[0]).add(BigDecimal.valueOf(vs[1])).doubleValue();
		}
		return Arrays.stream(vs).mapToObj(BigDecimal::valueOf).reduce(BigDecimal::add).get().doubleValue();
	}

	/**
	 * 运算：减 -
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static double subtract(double ...vs) {
		if (vs == null) {
			return 0D;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return BigDecimal.valueOf(vs[0]).subtract(BigDecimal.valueOf(vs[1])).doubleValue();
		}
		return Arrays.stream(vs).mapToObj(BigDecimal::valueOf).reduce(BigDecimal::subtract).get().doubleValue();
	}

	/**
	 * 运算：乘 *
	 *
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static double multiply(double ...vs) {
		if (vs == null) {
			return 0D;
		}
		if (vs.length == 1) {
			return vs[0];
		}
		if (vs.length == 2) {
			return BigDecimal.valueOf(vs[0]).multiply(BigDecimal.valueOf(vs[1])).doubleValue();
		}
		return Arrays.stream(vs).mapToObj(BigDecimal::valueOf).reduce(BigDecimal::multiply).get().doubleValue();
	}

	/**
	 * 运算：除 /
	 *
	 * @param len	小数位数
	 * @param mode	进位模式
	 * @param vs	运算数：2个及以上，除数 == 0 = 被除数（不再抛异常 java.lang.ArithmeticException: / by zero）
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static double divide(int len, RoundingMode mode, double ...vs) {
		return Arrays.stream(vs).mapToObj(BigDecimal::valueOf).reduce((a, b) -> {
			if (DecimalUtil.isEmpty(b)) {
				return a.setScale(len, mode);
			}else{
				return a.divide(b, len, mode);
			}
		}).get().doubleValue();
	}

	/**
	 * 运算-除 /
	 *
	 * @param len	小数位数（四舍五入）
	 * @param vs	运算数
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2019年11月11日
	 */
	public static double divide(int len, double ...vs) {
		return divide(len, RoundingMode.HALF_UP, vs);
	}

	/**
	 * 判断区间 min <= v <= max
	 *
	 * @param v
	 * @param min
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static boolean isRange(double v, double min, double max) {
		return v >= min && v <= max;
	}

	/**
	 * 限定区间 min <= v <= max
	 *
	 * @param v
	 * @param min
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static double range(double v, double min, double max) {
		if(v < min){
			return min;
		}else {
			return Math.min(v, max);
		}
	}

	/**
	 * 判断区间 0 <= v <= max
	 *
	 * @param v
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static boolean isRange(double v, double max) {
		return isRange(v, 0, max);
	}

	/**
	 * 获取区间 0 <= v <= max
	 *
	 * @param v
	 * @param max
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月5日
	 */
	public static double range(double v, double max) {
		return range(v, 0, max);
	}
}
